#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = "Naich An (An@Naich.org)"

#add the path to sys.path so *.py in the same dir could be found
import sys
sys.path.append('/home/naich/web/')

import web
import random
import config #import the settings


##########################settings################################




#debug setting
web.config.debug = True
#templates folder setting
render = web.template.render('/home/naich/web/page/')
#website structure
urls = (
	'/','index',
	'/favicon.ico','favicon',
	'/login','login',
	'/redirect','redirect',
	'/userlist','userlist',
	'/home','home',
	'/choose','choose',
	'/store','store',
	'/waiting','waiting',
	'/result','result',
	'/admin','admin',
	'/stat','stat',
	'/day(.)','day',
)
#define app
app = web.application(urls,locals())

#redef notfound information	
def notfound():
	return web.notfound(render.notfound())
app.notfound = notfound

#########################functions####################################

#get the current complete roundnum
def getRound():
	cur = config.cursor()
	cur.execute("SELECT round FROM gameinfo ORDER BY round DESC LIMIT 1")
	roundnow = cur.fetchone()
	if roundnow:
		return roundnow[0]
	else:
		return 0
	
#get the user's lastest choice roundnum
def getMyRound(username):
	cur = config.cursor()
	cur.execute("SELECT round FROM gamedata WHERE name = '%s' ORDER BY round DESC LIMIT 1"%username)
	myRound = cur.fetchone()
	#if there are my datas in the database, return it , else return 0
	if myRound:
		return myRound[0]
	else:
		return 0 

#get the user's latest score
def getMyScore(username):
	cur = config.cursor()
	cur.execute("SELECT score FROM user WHERE name = '%s'"%username)
	myScore = cur.fetchone()
	#if there are my datas in the database, return it , else return 0
	if myScore:
		return myScore[0]
	else:
		return 0 

#see if the user win or lose the last round
def getMyStatus(username):
	cur = config.cursor()
	roundnow = getRound()
	cur.execute("SELECT winroom FROM gameinfo WHERE round = %d"%roundnow)
	winroom = cur.fetchone()[0]
	cur.execute("SELECT choice FROM gamedata WHERE round = %d  AND name = '%s'"%(roundnow, username))
	choice = cur.fetchone()[0]
	return (choice == winroom)


#############################pages#####################################
	
#index, no special meanings	
class index:
	def GET(self):
		web.setcookie('name', "")
#		raise web.seeother('/login')
		cur = config.cursor()
		cur.execute('SELECT counter FROM counter')
		counter = cur.fetchone()[0]
		return render.index(counter)

#def the favicon of the site			
class favicon:
	def GET(self):
		raise web.redirect('/static/favicon.ico')

#login page		
class login:
	def GET(self):
		if web.cookies().get('name'):
			return render.login(web.cookies().get('name'))
		else:
			return render.login("")

#save the login info and redirect to a new page.			
class redirect:
	def POST(self):
		cur = config.cursor()
		i = web.input()
		if not i.name:
			raise web.seeother('/')
		cur.execute("SELECT name FROM user WHERE 1")
		#if name not in the userlist , create new
		if (i.name,) not in cur.fetchall():
				cur.execute("INSERT INTO user(name,passwd) VALUES('%s','%s')"%(i.name,i.passwd))
				web.setcookie('name',i.name)
				raise web.seeother('/home')
		#if in the userlist, check its passwd		
		else:
			cur.execute("SELECT passwd FROM user WHERE name = '%s'"%i.name)
			if i.passwd != cur.fetchone()[0]:
				return "WRONG PASSWORD!"
			else:
				web.setcookie('name',i.name)
				raise web.seeother('/home')
				
#homepage, show once before the game starts
class home:
	def GET(self):
		if web.cookies().get('name'): 
			return render.home("Welcome, %s"%web.cookies().get('name'))		
		else:
		#if not logged, redirect to login page
			raise web.seeother('/login')
		
#choose a room	
class choose:
	def GET(self):
		return render.choose("%s"%web.cookies().get('name'))

#store the users' choice and redirect to wait page 
class store:
	def POST(self):
		cur = config.cursor()
		i = web.input()
		if i:
			username = web.cookies().get('name')
			if not username:
				raise web.seeother('/')
			#func 'getRound' get the previous roundnum, so plus 1
			roundnum = getRound() + 1
			if getMyRound(username) == roundnum:
				raise web.seeother('/waiting')
			else:
				cur.execute("INSERT INTO gamedata(round, name, choice) VALUES(%d, '%s', '%s')"%(roundnum, username, i.choice))
				raise web.seeother('/waiting')
		else:
			raise web.seeother('/choose')

#waiting for everone to complete the game.
class waiting:
	def GET(self):
		username = web.cookies().get('name')
		#if the winning information is out, then redirect to result
		if getMyRound(username) == getRound():
			raise web.seeother('/result')
		else:
			return render.waiting(username)
			
#show the result of a specific user
class result:
	def GET(self):
		username = web.cookies().get('name')
		myScore = getMyScore(username)
		myStatus = getMyStatus(username)
		return render.result(username, myScore, myStatus)

##########################developers and admins only######################

#admin page, to see different data and decide which room to win
class admin:
	def GET(self):
		cur = config.cursor()
		if web.ctx.ip != '127.0.0.1' and web.ctx.ip != '::1':
			return "Wrong Way!"+web.ctx.ip
		#this is a new round, so +1
		roundnum = getRound() + 1
		cur.execute("SELECT name,choice FROM gamedata WHERE round = %d ORDER BY name ASC"%roundnum) 
		userdata = cur.fetchall()
		#calculate how many 1 and 2 are there in the choices
		userChoices = [data[1] for data in userdata]
		normal1 = userChoices.count(1)
		normal2 = userChoices.count(2)
		#calculate the beta1 and beta2
		beta1 = 0
		beta2 = 0
		for i in range(0, config.betaAll):
			#get a sample of maxmun 5. 
			aSample = random.sample(userChoices, min(5, len(userChoices)))
			#if choice == 2 is more , then the agent choose room 1.
			if sum(aSample) > len(aSample) * 1.5:
				beta1 += 1
			else:
				beta2 += 1
		#calculate the winroom from the beta
		if (normal1 + beta1) / config.M1 > (normal2 + beta2) / config.M2:
			winroom = 2
		else:
			if (normal1 + beta1) / config.M1 < (normal2 + beta2) / config.M2:
				winroom = 1
			else:
				winroom = random.choice([1,2])
		
		i = web.input()
		#if the the admin send the data ,then add the data into the database
		if i:
			#update the scores
			for user in userdata:
				if user[1] == int(i.winroom):
					cur.execute("SELECT score FROM user WHERE name = '%s'"%user[0])
					userScore = cur.fetchone()[0] + 10
					cur.execute("UPDATE user SET score = %d WHERE name = '%s'"%(userScore, user[0]))
				else:
					pass
			#update the gameinfo
			dataset = (roundnum, config.M1/config.M2, i.beta1, i.beta2, i.normal1, i.normal2, i.winroom)
			sql = "INSERT INTO gameinfo(round, beta, beta1, beta2, normal1, normal2, winroom) VALUES(%s, %s, %s, %s, %s, %s, %s)"
			cur.execute(sql%dataset)
		return render.admin(userdata,normal1,normal2,beta1,beta2,winroom)

#show the stats of the game
class stat:
	def GET(self):
		cur = config.cursor()
		cur.execute("SELECT round,normal1,normal2,beta1,beta2,beta FROM gameinfo WHERE 1 ORDER BY round ASC")
		dataset =  cur.fetchall()
		sigma = []
		for r in dataset:
			N = r[1] + r[2] + r[3] + r[4]
			Ns1 = r[5] * N / (r[5] + 1) 
			Ns2 = N / (r[5] + 1)
			sigma += [((r[1] + r[3] - Ns1)**2 + (r[2] + r[4] - Ns2)**2) / (2*N)]
		return sigma
		
		
#show userlist, developers only page			
class userlist:
	def GET(self):
		cur = config.cursor()
		cur.execute("SELECT * FROM user WHERE 1")
		userinfo = cur.fetchall()
		return render.userlist(userinfo)
		
#give the data
class day:
	def GET(self,daynumber):
		cur = config.cursor()
		cur.execute("SELECT counter FROM counter")
		counter = cur.fetchone()[0]
		cur.execute("UPDATE counter SET counter = %d"%(counter + 1))
		raise web.seeother('/static/day'+daynumber+'.sql')
		


#run the web server
application = app.wsgifunc()



